#pragma once
#include "log.h"
#include "MyUnitGroup.h"
#include "MicroUnitData.h"
#include <math.h>
#include <algorithm>
using namespace std;

namespace scai {
	
	struct RemainingHPObjective {
		int squadSize;
		int maxHp;
		int eMaxHp;

		RemainingHPObjective(int maxHp, int eMaxHp): maxHp(maxHp), eMaxHp(eMaxHp) {}

		double calc(std::vector<BWAPI::Unit*> remaining) {
			double avaragePercent = 0;
			
			if (remaining.size() != 0) {
				for (int i=0; i < remaining.size(); i++) {
					avaragePercent += (double)remaining.at(i)->getHitPoints();
				}
				avaragePercent = avaragePercent / (double)maxHp;
			}
			else {
				std::set<BWAPI::Unit*>::iterator enemyIt;
				std::set<BWAPI::Unit*> enem = BWAPI::Broodwar->enemy()->getUnits();
				for (enemyIt = enem.begin(); enemyIt != enem.end(); enemyIt++) {
					avaragePercent += (double)(*enemyIt)->getHitPoints();
				}
				avaragePercent = (avaragePercent / (double)eMaxHp) * (double)-1;
			}

			return avaragePercent;
		}
		
		double getMax() { return (double)1; }
		double getMin() { return (double)-1; }
	};

	struct EconomicEfficiencyObjective {
		EconomicEfficiencyObjective() {}

		double calc() {
			int myScore = BWAPI::Broodwar->self()->getKillScore();
			int hisScore = BWAPI::Broodwar->enemy()->getKillScore();
			if (myScore > hisScore) {
				return (myScore-hisScore)/((double)(BWAPI::Broodwar->enemy()->getUnitScore()*2));
			}
			else {
				return -1.0 * (myScore-hisScore)/((double)(BWAPI::Broodwar->self()->getUnitScore()*2));
			}
		}

		double EconomicEfficiencyObjective::getMax() { return (double)1; }
		double EconomicEfficiencyObjective::getMin() { return (double)-1; }
	};

	struct KeepUnitsAliveObjective {
		int squadSize;
		vector<int> deathTimings;

		KeepUnitsAliveObjective(int squadSize): squadSize(squadSize) {
			deathTimings.reserve(squadSize);
		}

		void updateKill() {
			deathTimings.push_back(BWAPI::Broodwar->elapsedTime());
		}
		
		double calc() { 
			double t = 0;
			int totalTime = BWAPI::Broodwar->elapsedTime();

			for (vector<int>::iterator it = deathTimings.begin(); it != deathTimings.end(); it++) {
				t += *it / (double)totalTime;
			}

			return t / (double)squadSize;
		}

		double getMax() { return (double)1; }
		double getMin() { return (double)0; }
	};

	struct DPSEfficiency {
		int squadSize;
		double efficiency;

		DPSEfficiency(int squadSize): squadSize(squadSize) {}
		
		void updateBeforeDead(double e) {
			efficiency += e;
		}

		double calc() {
			return efficiency / (double)squadSize;
		}

		double getMax() { return (double)1; }
		double getMin() { return (double)0; }
	};
}